home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 6 / CU Amiga Magazine's Super CD-ROM 06 (1996)(EMAP Images)(GB)(Track 1 of 4)[!][issue 1997-01].iso / cucd / prog / gnu-c / ixpipe / ixpipe-handler.c < prev    next >
C/C++ Source or Header  |  1994-02-15  |  10KB  |  375 lines

  1. ;/* 
  2. failat 1
  3. gcc -O2 -c ixpipe-handler.c -Igcc:include20 -Wall ;-DDEBUG
  4. gcc -nostdlib ixpipe-handler.o -o ixpipe-handler -lc ;-ldebug -lsmall -lc
  5. quit
  6. */
  7. #include <sys/types.h>
  8. #include <sys/file.h>
  9. #include <sys/signal.h>
  10. #include <sys/stat.h>
  11. #include <errno.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>
  14. #include <string.h>
  15. #include <setjmp.h>
  16. #include <stdio.h>
  17.  
  18. #include <exec/types.h>
  19. #include <exec/lists.h>
  20. #include <exec/ports.h>
  21. #include <exec/execbase.h>
  22. #include <dos/dosextens.h>
  23. #include <dos/filehandler.h>
  24. #include <packets.h>
  25.  
  26. #include <inline/exec.h>
  27.  
  28. /* BCPL-like packet handling functions, very useful ;-) */
  29. #include "misc.h"
  30.  
  31. #ifdef DEBUG
  32. #define dprintf(fmt, args...) kprintf(fmt, ##args)
  33. #else
  34. #define dprintf(fmt, args...)
  35. #endif
  36.  
  37. /* this is our custom packet, which passes along an ixemul-private file
  38.    id, which we then use to clone that file into our file-table space.
  39.    All later operations are then performed on file-descriptors as usual ;-)) */
  40. #define ACTION_IXEMUL_MAGIC    0x4242    /* *very* magic ;-)) */
  41.  
  42. #define DOS_TRUE        -1
  43. #define DOS_FALSE         0
  44.  
  45. /* we require at least ixemul.library v39.41 */
  46. #define NEEDED_IX_VERSION    39    /* or better */
  47. #define NEEDED_IX_REVISION    41    /* or better */
  48.  
  49. int handler_mainloop (struct DeviceNode *dev_node, struct Process *me,
  50.               int *errno);
  51. static int __errno_to_ioerr (int err);
  52.  
  53. /* guarantee that the first location in the code hunk is a jump to where
  54.    we start, and not some shared string that just happend to land at
  55.    location 0... */
  56. asm (".text; jmp pc@(_ENTRY-.+2);");
  57.  
  58. struct Library *ixemulbase = 0;
  59. struct ExecBase *SysBase;
  60.  
  61. static int
  62. ENTRY (void)
  63. {
  64.   struct Library *ixbase;
  65.   struct Process *me;
  66.   struct DosPacket *startup_packet;
  67.   struct DeviceNode *dev_node;
  68.   int errno;
  69.  
  70.   SysBase = *(struct ExecBase **) 4;
  71.   me = (struct Process *) FindTask (0);
  72.  
  73.   dprintf("ixp-$%lx: waiting for startup-packet\n", me);
  74.  
  75.   /* wait for the startup packet */
  76.   startup_packet = taskwait (me);
  77.  
  78.   dprintf("ixp-$%lx: got startup packet\n", me);
  79.  
  80.   ixbase = OpenLibrary ("ixemul.library", NEEDED_IX_VERSION);
  81.   if (ixbase)
  82.     {
  83.       if (ixbase->lib_Version == NEEDED_IX_VERSION &&
  84.           ixbase->lib_Revision < NEEDED_IX_REVISION)
  85.     CloseLibrary (ixbase);
  86.       else
  87.     {
  88.       /* make the external library glue work */
  89.       ixemulbase = ixbase;
  90.       dev_node = BTOCPTR (startup_packet->dp_Arg3);
  91.       dev_node->dn_Task = &me->pr_MsgPort;
  92.       returnpkt (startup_packet, me, DOS_TRUE, 0);
  93.       
  94.       dprintf ("ixp-$%lx: init ok, entering handler mainloop\n", me);
  95.       /* ignore the result _exit() might pass to us.
  96.              pass our device node as `argc' to handler_mainloop() */
  97.       ix_exec_entry (dev_node, me, &errno, &errno, handler_mainloop);
  98.       CloseLibrary (ixbase);
  99.       return 0;
  100.     }
  101.     }
  102.     
  103. /*  returnpkt (startup_packet, me, DOS_FALSE, ERROR_OBJECT_NOT_FOUND);*/
  104.   dprintf ("ixp-$%lx: init-error\n", me);
  105.   returnpkt (startup_packet, me, DOS_FALSE, ERROR_BAD_STREAM_NAME);
  106. }
  107.  
  108.  
  109. void
  110. dummy_sighandler ()
  111. {}
  112.  
  113. jmp_buf jmpbuf;
  114.  
  115. void
  116. panic_sighandler (int sig)
  117. {
  118.   longjmp (jmpbuf, sig);
  119. }
  120.  
  121. int 
  122. handler_mainloop (struct DeviceNode *dev_node, struct Process *me, int *errno)
  123. {
  124.   struct DosPacket *dp;
  125.   struct MsgPort *our_mp = &me->pr_MsgPort;
  126.   int i;
  127.  
  128.   for (i = 1; i < SIGMSG; i++)
  129.     signal (i, panic_sighandler);
  130.   /* disable ^C propagation as good as we can... */
  131.   signal (SIGMSG, dummy_sighandler);
  132.      
  133.   /* terminated by ACTION_END, Close() that is */
  134.   for (;;)
  135.     {
  136.       if (i = setjmp (jmpbuf))
  137.         {
  138.       dprintf ("ixp-$%lx: SIGNAL %ld\n", me, i);
  139.       if (dp->dp_Type == ACTION_WRITE && i == SIGPIPE)
  140.         {
  141.           Signal (dp->dp_Port->mp_SigTask, SIGBREAKF_CTRL_C);
  142.           returnpkt (dp, me, -1, 0); /* return EOF */
  143.           continue;
  144.         }
  145.      
  146.  
  147.       /* should look like `SIG' plus number ;-) */
  148.       returnpkt (dp, me, DOS_FALSE, 516000 + i);
  149.       continue;
  150.     }
  151.  
  152.       dprintf ("ixp-$%lx: Waiting for packet...\n", me);
  153.       while (!(dp = taskwait (me))) ;
  154.  
  155.       /* find out what they want us to do.... */
  156.       switch (dp->dp_Type)
  157.         {
  158.         case ACTION_IXEMUL_MAGIC:
  159.       {
  160.         /* this is sort of an `Open', that is, we fill out a struct
  161.            FileHandle. The reason I didn't chose to `abuse' the various
  162.            ACTION_FIND{INPUT,OUTPUT} packets is simple: I want an
  163.            ordinary Open() call to fail! The semantics are, that you
  164.                pass a hex string describing the id as name. */
  165.             int fd;
  166.             char name[255];    /* a BSTR can't address more ;-) */
  167.         u_char *cp;
  168.             u_long id;
  169.             struct FileHandle *fh;
  170.             
  171.             fh = BTOCPTR (dp->dp_Arg1);
  172.          cp = BTOCPTR (dp->dp_Arg3);
  173.          if (cp && fh)
  174.            {
  175.          bcopy (cp + 1, name, *cp);
  176.           name[*cp] = 0;
  177.         /* in case the device-qualifier is still contained in the name */
  178.         cp = index (name, ':');
  179.         if (cp)
  180.           cp++;
  181.         else
  182.           cp = name;
  183.         if (sscanf (cp, "%x", &id) == 1)
  184.           {
  185.             /* this fcntl() command does not require a valid 
  186.                descriptor. It's quite unique in this behavior... */
  187.             fd = fcntl (-1, F_INTERNALIZE, id);
  188.             if (fd >= 0)
  189.               {
  190.                 fh->fh_Arg1 = fd;
  191.                 fh->fh_Type = our_mp;
  192.                 fh->fh_Port = 0; /* we're not interactive, are we? */
  193.  
  194.             dprintf ("ixp-$%lx: successful open, fd = %ld\n", me, fd);
  195.             /* Setting the dn_Task field back to 0 makes each 
  196.                successive opening of IXPIPE: spawn a new handler.
  197.                This is essential, or opening would block, if the
  198.                handler is inside a read/write wait */
  199.                 dev_node->dn_Task = 0;
  200.                 returnpkt (dp, me, DOS_TRUE, 0);
  201.                 break;
  202.               }
  203.           }
  204.           }
  205.         dprintf ("ixp-$%lx: open failed somehow.. \n", me);
  206.         /* default is to return object-not-found.. */
  207.         returnpkt (dp, me, DOS_FALSE, ERROR_OBJECT_NOT_FOUND);
  208.         break;
  209.       }
  210.  
  211.  
  212.     /* all the following packets operate on file descriptors obtained
  213.        in ACTION_IXEMUL_MAGIC. */
  214.        
  215.     case ACTION_READ:
  216.       dprintf ("ixp-$%lx: read (%ld, $%lx, %ld)\n", me, dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  217.       dp->dp_Res1 = read (dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  218.       if (dp->dp_Res1 < 0)
  219.         dp->dp_Res2 = __errno_to_ioerr (*errno);
  220.       else
  221.         dp->dp_Res2 = 0;
  222.       returnpktplain (dp, me);
  223.       break;
  224.  
  225.     case ACTION_WRITE:
  226.       dprintf ("ixp-$%lx: write (%ld, $%lx, %ld)\n", me, dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  227.       dp->dp_Res1 = write (dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  228.       if (dp->dp_Res1 < 0)
  229.         dp->dp_Res2 = __errno_to_ioerr (*errno);
  230.       else
  231.         dp->dp_Res2 = 0;
  232.       returnpktplain (dp, me);
  233.       break;
  234.  
  235.     case ACTION_SEEK:
  236.       dprintf ("ixp-$%lx: lseek (%ld, %ld, %ld)\n", me, dp->dp_Arg1, (char *) dp->dp_Arg2, dp->dp_Arg3);
  237.       /* we have to return the previous offset, contrary to Unix which
  238.          returns the offset after seek operation */
  239.       dp->dp_Res1 = lseek (dp->dp_Arg1, 0, SEEK_CUR);
  240.       if (dp->dp_Res1 >= 0)
  241.         {
  242.           lseek (dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3 + 1);
  243.           dp->dp_Res2 = 0;
  244.         }
  245.       else
  246.         dp->dp_Res2 = __errno_to_ioerr (*errno);
  247.       returnpktplain (dp, me);
  248.       break;
  249.  
  250.     /* a little present for the growing number of >1.3 users out there */
  251.     case ACTION_EXAMINE_FH:
  252.       {
  253.          struct FileInfoBlock *fib = BTOCPTR (dp->dp_Arg2);
  254.         struct stat stb;
  255.         long time;
  256.         
  257.         dprintf ("ixp-$%lx: fstat (%ld, )\n", me, dp->dp_Arg1);
  258.             fib = BTOCPTR (dp->dp_Arg2);
  259.         dp->dp_Res1 = fstat (dp->dp_Arg1, &stb) == 0 ? DOS_TRUE : DOS_FALSE;
  260.         dp->dp_Res2 = (dp->dp_Res1 == DOS_FALSE) ? __errno_to_ioerr (*errno) : 0;
  261.         if (dp->dp_Res1 == DOS_TRUE)
  262.           {
  263.         fib->fib_DiskKey = stb.st_ino;
  264.         /* on the packet level, fib's contain the name as a BSTR */
  265.         strcpy (fib->fib_FileName + 1, "you won't be able to reopen me anyway");
  266.         fib->fib_FileName[0] = strlen (fib->fib_FileName + 1);
  267.             fib->fib_Protection = stb.st_amode; /* nice we kept it ;-)) */
  268.         fib->fib_Size = stb.st_size;
  269.         fib->fib_NumBlocks = stb.st_blocks;
  270.         time = stb.st_mtime - (8*365+2)*24*3600; /* offset to unix-timesystem */
  271.         fib->fib_Date.ds_Tick = (time % 60) * TICKS_PER_SECOND;
  272.         time /= 60;
  273.         /* minutes per day, not minutes per hour! */
  274.         fib->fib_Date.ds_Minute = time % (60 * 24);
  275.         time /= 60 * 24;
  276.         fib->fib_Date.ds_Days = time;
  277.         fib->fib_Comment[0] = 0;
  278.         /* reserved stuff should normally be zero'd, so do right this */
  279.         bzero (fib->fib_Reserved, sizeof (fib->fib_Reserved));
  280.  
  281.         /* this is a bit tricky ;-)) 
  282.            Wondering what AmigaDOS programs might do when they're faced
  283.            with a directory type when examining a filehandle.... */
  284.         if (S_ISDIR (stb.st_mode))
  285.           fib->fib_DirEntryType = ST_USERDIR;
  286.         else if (S_ISCHR (stb.st_mode))
  287.           fib->fib_DirEntryType = ST_PIPEFILE;
  288.         else if (S_ISLNK (stb.st_mode))
  289.           fib->fib_DirEntryType = ST_SOFTLINK;
  290.         else
  291.           fib->fib_DirEntryType = ST_FILE;
  292.  
  293.         fib->fib_EntryType = fib->fib_DirEntryType;
  294.           }
  295.         returnpktplain (dp, me);
  296.         break;
  297.       }
  298.  
  299.     case ACTION_END:
  300.       dprintf ("ixp-$%lx: close (%ld)\n", me, dp->dp_Arg1);
  301.       close (dp->dp_Arg1);
  302.       returnpkt (dp, me, DOS_TRUE, 0);
  303.       /* terminates the handler */
  304.       Forbid ();
  305.       return;
  306.       
  307.     default:
  308.       dprintf ("ixp-$%lx: returning unknown packet %ld\n", me, dp->dp_Type);
  309.       returnpkt (dp, me, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
  310.       break;
  311.     }
  312.     }
  313. }
  314.  
  315.  
  316. static int
  317. __errno_to_ioerr (int err)
  318. {
  319.   switch (err)
  320.     {
  321.     case EAGAIN:
  322.       return ERROR_TASK_TABLE_FULL;
  323.       
  324.     case ENOMEM:
  325.       return ERROR_NO_FREE_STORE;
  326.  
  327.     case E2BIG:
  328.       return ERROR_LINE_TOO_LONG;
  329.       
  330.     case ENOEXEC:
  331.       return ERROR_FILE_NOT_OBJECT;
  332.       
  333.     case EEXIST:
  334.       return ERROR_OBJECT_EXISTS;
  335.       
  336.     case ENOENT:
  337.       return ERROR_OBJECT_NOT_FOUND;
  338.       
  339.     default:
  340.     case ENODEV:
  341.     case EIO:
  342.       return ERROR_ACTION_NOT_KNOWN;
  343.       
  344.     case EINVAL:
  345.       return ERROR_OBJECT_WRONG_TYPE;
  346.       
  347.     case EROFS:
  348.       return ERROR_DISK_WRITE_PROTECTED;
  349.       
  350.     case EXDEV:
  351.       return ERROR_RENAME_ACROSS_DEVICES;
  352.       
  353.     case ENOTEMPTY:
  354.       return ERROR_DIRECTORY_NOT_EMPTY;
  355.       
  356.     case ELOOP:
  357.       return ERROR_TOO_MANY_LEVELS;
  358.       
  359.     case ENXIO:
  360.       return ERROR_DEVICE_NOT_MOUNTED;
  361.       
  362.     case ESPIPE:
  363.       return ERROR_SEEK_ERROR;
  364.       
  365.     case ENAMETOOLONG:
  366.       return ERROR_COMMENT_TOO_BIG;
  367.       
  368.     case ENOSPC:
  369.       return ERROR_DISK_FULL;
  370.       
  371.     case EACCES:
  372.       return ERROR_READ_PROTECTED;    /* could as well be one of the others... */
  373.     }
  374. }
  375.